home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / CPP / WFC010.ZIP / SRC / SOCKETS.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-07  |  23.1 KB  |  912 lines

  1. #include <wfc.h>
  2. #pragma hdrstop
  3.  
  4. /*
  5. ** Author: Samuel R. Blackburn
  6. ** CI$: 76300,326
  7. ** Internet: sammy@sed.csc.com
  8. **
  9. ** You can use it any way you like as long as you don't try to sell it.
  10. **
  11. ** Any attempt to sell WFC in source code form must have the permission
  12. ** of the original author. You can produce commercial executables with
  13. ** WFC but you can't sell WFC.
  14. **
  15. ** Copyright, 1995, Samuel R. Blackburn
  16. **
  17. ** $Workfile: $
  18. ** $Revision: $
  19. ** $Modtime: $
  20. */
  21.  
  22. #if defined( _DEBUG )
  23. #undef THIS_FILE
  24. static char BASED_CODE THIS_FILE[] = __FILE__;
  25. #define new DEBUG_NEW
  26. #endif
  27.  
  28. CSimpleSocket::CSimpleSocket()
  29. {
  30.    m_Initialize();
  31. }
  32.  
  33. CSimpleSocket::~CSimpleSocket()
  34. {
  35.    TRACE( "Destroying a CSimpleSocket object\n" );
  36.    Close();
  37. }
  38.  
  39. void CSimpleSocket::Close( void )
  40. {
  41.    ASSERT_VALID( this );
  42.  
  43.    if ( m_SocketID != INVALID_SOCKET )
  44.    {
  45.       ::closesocket( m_SocketID );
  46.       m_SocketID = INVALID_SOCKET;
  47.       m_hFile    = CFile::hFileNull;
  48.    }
  49.  
  50.    Name.Empty();
  51.    Address.Empty();
  52.    AliasList.RemoveAll();
  53. }
  54.  
  55. #if defined( _DEBUG )
  56.  
  57. void CSimpleSocket::Dump( CDumpContext &dump_context ) const
  58. {
  59.    CDummyFile::Dump( dump_context );
  60.  
  61.    dump_context << "Address = \""    << Address    << "\"\n";
  62.    dump_context << "Name = \""       << Name       << "\"\n";
  63.    dump_context << "m_PortName = \"" << m_PortName << "\"\n";
  64.    dump_context << "m_PortNumberInNetworkByteOrder ="  << ::ntohs( m_PortNumberInNetworkByteOrder ) << "\n";
  65.    dump_context << "m_SocketID = " << m_SocketID << "\n";
  66.  
  67.    int index = 0;
  68.    int number_of_aliases = AliasList.GetCount();
  69.  
  70.    dump_context << "AliasList conains " << number_of_aliases << " aliases.\n";
  71.  
  72.    CString string;
  73.  
  74.    POSITION pos = AliasList.GetHeadPosition();
  75.  
  76.    while( pos != NULL )
  77.    {
  78.       string = AliasList.GetNext( pos );
  79.       dump_context << index << ". \"" << string << "\"\n";
  80.  
  81.       index++;
  82.    }
  83. }
  84.  
  85. #endif // _DEBUG
  86.  
  87. void CSimpleSocket::GetAddress( CString& _address ) const
  88. {
  89.    ASSERT_VALID( this );
  90.  
  91.    _address = Address;
  92. }
  93.  
  94. SOCKET CSimpleSocket::GetID( void ) const
  95. {
  96.    ASSERT_VALID( this );
  97.  
  98.    return( m_SocketID );
  99. }
  100.  
  101. void CSimpleSocket::GetName( CString& _host_name ) const
  102. {
  103.    ASSERT_VALID( this );
  104.  
  105.    _host_name = Name;
  106. }
  107.  
  108. void CSimpleSocket::GetPort( short& _port_number ) const
  109. {
  110.    ASSERT_VALID( this );
  111.  
  112.    _port_number = ::ntohs( m_PortNumberInNetworkByteOrder );
  113. }
  114.  
  115. void CSimpleSocket::GetPort( CString& _port_name ) const
  116. {
  117.    ASSERT_VALID( this );
  118.  
  119.    _port_name = m_PortName;
  120. }
  121.  
  122. BOOL CSimpleSocket::IsDataWaiting( void )
  123. {
  124.    ASSERT_VALID( this );
  125.  
  126.    if ( m_SocketID == INVALID_SOCKET )
  127.    {
  128.       return( FALSE );
  129.    }
  130.  
  131.    int bytes_for_this_socket = 0;
  132.    int socket_status         = 0;
  133.  
  134.    FD_SET socket_in;
  135.  
  136.    TIMEVAL time_out;
  137.  
  138.    /*
  139.    ** Initialize the data structures
  140.    */
  141.  
  142.    FD_ZERO( (LPFD_SET) &socket_in );
  143.  
  144.    time_out.tv_sec  = 0;
  145.    time_out.tv_usec = 0;
  146.  
  147.    /*
  148.    ** Set socket_in to specify that we are looking for data on socket port_id
  149.    */
  150.  
  151.    FD_SET( m_SocketID, (LPFD_SET) &socket_in );
  152.  
  153.    /*
  154.    ** See if data is waiting
  155.    */
  156.  
  157.    socket_status = ::select( 0, &socket_in, NULL, NULL, &time_out );
  158.  
  159.    if ( socket_status == SOCKET_ERROR )
  160.    {
  161.       TRACE2( "CSimpleSocket::IsDataWaiting(), Can't select() at line %d of %s\n", __LINE__, __FILE__ );
  162.  
  163.       m_ErrorCode = ::WSAGetLastError();
  164.       return( FALSE );
  165.    }
  166.  
  167.    if ( socket_status == 0 )
  168.    {
  169.       /*
  170.       ** No Data is waiting on any socket in the OS
  171.       */
  172.  
  173.       return( FALSE );
  174.    }
  175.  
  176.    /*
  177.    ** Welp, data is waiting for *A* socket. It may not be *our* socket. A socket in the
  178.    ** operating system has data waiting in it. Let's see if it happens to be *our* socket.
  179.    */
  180.  
  181.    bytes_for_this_socket = ::FD_ISSET( m_SocketID, &socket_in );
  182.    
  183.    if ( bytes_for_this_socket == 0 )
  184.    {
  185.       /*
  186.       ** There is data for a socket somewhere in the system but not for our socket
  187.       */
  188.  
  189.       return( FALSE );
  190.    }
  191.  
  192.    return( TRUE );
  193. }
  194.  
  195. void CSimpleSocket::m_Initialize( void )
  196. {
  197.    ASSERT_VALID( this ) ;
  198.  
  199.    TRACE( "CsimpleSocket::m_Initialize()\n" );
  200.  
  201.    /*
  202.    ** Make sure everything is empty
  203.    */
  204.  
  205.    m_PortNumberInNetworkByteOrder = 0;
  206.    m_SocketID                     = INVALID_SOCKET;
  207.    m_hFile                        = CFile::hFileNull;
  208.  
  209.    Address.Empty();
  210.    Name.Empty();
  211.    m_PortName.Empty();
  212.    AliasList.RemoveAll();
  213. }
  214.  
  215. UINT CSimpleSocket::Read( VOID *buffer, const int size_of_buffer )
  216. {
  217.    ASSERT_VALID( this );
  218.    ASSERT( buffer != NULL );
  219.    ASSERT( size_of_buffer > 0 );
  220.  
  221.    if ( buffer == NULL )
  222.    {
  223.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  224.       return( 0 );
  225.    }
  226.  
  227.    if ( m_SocketID != INVALID_SOCKET )
  228.    {
  229.       int number_of_bytes_read = 0;
  230.  
  231.       ::ZeroMemory( buffer, size_of_buffer );
  232.    
  233.       number_of_bytes_read = ::recv( m_SocketID, (char *) buffer, size_of_buffer, 0 );
  234.    
  235.       if ( number_of_bytes_read == SOCKET_ERROR )
  236.       {
  237.          TRACE( "CSimpleSocket::Read(), Error in recv() at line %d of %s\n", __LINE__, __FILE__ );
  238.  
  239.          m_ErrorCode = ::WSAGetLastError();
  240.          return( 0 );
  241.       }
  242.       
  243.       return( number_of_bytes_read );   
  244.    }
  245.    else
  246.    {
  247.       return( 0 );
  248.    }
  249. }
  250.  
  251. void CSimpleSocket::Read( CString& line_to_read )
  252. {
  253.    ASSERT_VALID( this );
  254.  
  255.    if ( m_SocketID != INVALID_SOCKET )
  256.    {
  257.       char character = 0x00;
  258.  
  259.       int number_of_bytes_read = 0;
  260.  
  261.       /*
  262.       ** Need to add CRLF checking!!!!
  263.       */
  264.  
  265.       while( character != LINE_FEED )
  266.       {
  267.          number_of_bytes_read = ::recv( m_SocketID, &character, 1, 0 );
  268.  
  269.          if ( number_of_bytes_read == SOCKET_ERROR )
  270.          {
  271.             TRACE( "CSimpleSocket::Read(), Error in recv() at line %d of %s\n", __LINE__, __FILE__ );
  272.  
  273.             m_ErrorCode = ::WSAGetLastError();
  274.             return;
  275.          }
  276.  
  277.          line_to_read += character;
  278.       }
  279.    }
  280. }
  281.  
  282. void CSimpleSocket::SetAddress( const char *address_string )
  283. {
  284.    /*
  285.    ** Called when a client connects to us. This function also fills in the
  286.    ** client's name for security checking.
  287.    */
  288.  
  289.    ASSERT_VALID( this );
  290.    ASSERT( address_string != NULL );
  291.    ASSERT( AfxIsValidString( address_string ) );
  292.  
  293.    if ( address_string == NULL )
  294.    {
  295.       Address.Empty();
  296.       return;
  297.    }
  298.  
  299.    CString address;
  300.  
  301.    address = address_string;
  302.  
  303.    /*
  304.    ** Address may contain "131.26.31.92" or "cheetah.sed.csc.com"
  305.    ** Given either, we must fill in host_name and IP_address
  306.    */
  307.  
  308.    LPHOSTENT host_entry_p = (LPHOSTENT) NULL;
  309.  
  310.    /*
  311.    ** See if it is in xxx.xxx.xxx.xxx form
  312.    */
  313.  
  314.    int index = 0;
  315.  
  316.    BOOL exit_loop = FALSE;
  317.  
  318.    while( index < address.GetLength() && exit_loop == FALSE )
  319.    {
  320.       if ( address[ index ] != '.' && ! isdigit( address[ index ] ) )
  321.       {
  322.          /*
  323.          ** The character is not a period and not a digit so it cannot meet the requirements
  324.          ** of xxx.xxx.xxx.xxx type address and therefore must be a host name
  325.          */
  326.  
  327.          exit_loop = TRUE;
  328.       }
  329.       else
  330.       {
  331.          index++;
  332.       }
  333.    }
  334.  
  335.    if ( exit_loop == TRUE )
  336.    {
  337.       /*
  338.       ** Tech Note: You must cast the CString object to a const char * when using things like printf()
  339.       */
  340.  
  341.       host_entry_p = ::gethostbyname( (const char *) address );
  342.    }
  343.    else
  344.    {
  345.       ULONG internet_address = 0L;
  346.  
  347.       internet_address = ::inet_addr( address );
  348.       host_entry_p = ::gethostbyaddr( (const char *) &internet_address, 4, PF_INET );
  349.    }
  350.  
  351.    if ( host_entry_p == (LPHOSTENT) NULL )
  352.    {
  353.       TRACE( "CSimpleSocket::set_address(), gethostby???() failed at line %d of %s\n", __LINE__, __FILE__ );
  354.  
  355.       m_ErrorCode = ::WSAGetLastError();
  356.       return;
  357.    }
  358.  
  359.    if ( exit_loop != TRUE )
  360.    {
  361.       Address = address;
  362.    }
  363.    else
  364.    {
  365.       LPSTR dotted_ip_address = (LPSTR) NULL;
  366.  
  367.       /*
  368.       ** You just gotta love the way Unix people thought . . . NOT!
  369.       */
  370.  
  371.       struct in_addr internet_address;
  372.  
  373.       internet_address.S_un.S_un_b.s_b1 = host_entry_p->h_addr_list[ 0 ][ 0 ];
  374.       internet_address.S_un.S_un_b.s_b2 = host_entry_p->h_addr_list[ 0 ][ 1 ];
  375.       internet_address.S_un.S_un_b.s_b3 = host_entry_p->h_addr_list[ 0 ][ 2 ];
  376.       internet_address.S_un.S_un_b.s_b4 = host_entry_p->h_addr_list[ 0 ][ 3 ];
  377.  
  378.       dotted_ip_address = ::inet_ntoa( internet_address );
  379.  
  380.       if ( dotted_ip_address == (LPSTR) NULL )
  381.       {
  382.          return;
  383.       }
  384.  
  385.       Address = dotted_ip_address;
  386.  
  387.       TRACE( "ip_address == \"%s\"\n", (const char *) Address );
  388.    }
  389.  
  390.    /*
  391.    ** We don't call set_name() because that function will call this function and we'll go into an endless loop
  392.    */
  393.  
  394.    Name = host_entry_p->h_name;
  395.  
  396.    /*
  397.    ** Now lets get the aliases for this fella
  398.    */
  399.  
  400.    AliasList.RemoveAll();
  401.  
  402.    index = 0;
  403.  
  404.    CString *new_string_p = NULL;
  405.  
  406.    while( host_entry_p->h_aliases[ index ] != (char *) NULL )
  407.    {
  408.       AliasList.AddTail( (const char *) host_entry_p->h_aliases[ index ] );
  409.       index++;
  410.    }
  411. }
  412.  
  413. void CSimpleSocket::SetID( const SOCKET id )
  414. {
  415.    ASSERT_VALID( this );
  416.  
  417.    m_SocketID = id;
  418.    m_hFile    = (UINT) id;
  419. }
  420.  
  421. void CSimpleSocket::SetName( const char *host_string )
  422. {
  423.    ASSERT_VALID( this );
  424.    ASSERT( host_string != NULL );
  425.  
  426.    if ( host_string == NULL )
  427.    {
  428.       Name.Empty();
  429.    }
  430.    else
  431.    {
  432.       Name = host_string;
  433.    }
  434. }
  435.  
  436. void CSimpleSocket::SetPort( const char *name_string )
  437. {
  438.    ASSERT_VALID( this );
  439.    ASSERT( name_string != NULL );
  440.  
  441.    if ( name_string == NULL )
  442.    {
  443.       m_PortName.Empty();
  444.       m_PortNumberInNetworkByteOrder = 0;
  445.       return;
  446.    }
  447.  
  448.    CString name;
  449.  
  450.    name = name_string;
  451.  
  452.    /*
  453.    ** Although not documented anywhere, the name of the protocol must be in lower case
  454.    ** If you look in the data file for getservbyname() [winnt/system32/drivers/etc/services]
  455.    ** you will notice that everything is in lower case. Gotta love Unix . . .
  456.    */
  457.  
  458.    name.MakeLower();
  459.  
  460.    /*
  461.    ** This routine sets port_name and m_PortNumberInNetworkByteOrder
  462.    */
  463.  
  464.    LPSERVENT service_entry_p = (LPSERVENT) NULL;
  465.  
  466.    service_entry_p = ::getservbyname( name, NULL );
  467.  
  468.    if ( service_entry_p == (LPSERVENT) NULL )
  469.    {
  470.       m_ErrorCode = ::WSAGetLastError();
  471.  
  472.       TRACE( "CSimpleSocket::set_server_port(), getservbyname() failed at line %d of %s, Last Error is %d\n", __LINE__, __FILE__, m_ErrorCode );
  473.  
  474.       return;
  475.    }
  476.  
  477.    m_PortName = name;
  478.    m_PortNumberInNetworkByteOrder = service_entry_p->s_port;
  479. }
  480.  
  481. void CSimpleSocket::SetPort( const short p )
  482. {
  483.    ASSERT_VALID( this );
  484.  
  485.    /*
  486.    ** This routine sets port_name and m_PortNumberInNetworkByteOrder
  487.    */
  488.  
  489.    m_PortNumberInNetworkByteOrder = ::htons( p );
  490.  
  491.    /*
  492.    ** Now go find a name for this port . . .
  493.    */
  494.  
  495.    LPSERVENT service_entry_p = (LPSERVENT) NULL;
  496.  
  497.    service_entry_p = ::getservbyport( m_PortNumberInNetworkByteOrder, NULL );
  498.  
  499.    if ( service_entry_p == (LPSERVENT) NULL )
  500.    {
  501.       TRACE( "CSimpleSocket::set_port(), getservbyport() failed at line %d of %s\n", __LINE__, __FILE__ );
  502.  
  503.       m_ErrorCode = ::WSAGetLastError();
  504.       m_PortName.Empty();
  505.       return;
  506.    }
  507.  
  508.    m_PortName = service_entry_p->s_name;
  509. }
  510.  
  511. void __stdcall CSimpleSocket::StartWindowsSockets( void )
  512. {
  513.    /*
  514.    ** Start WINSOCK
  515.    */
  516.  
  517.    WSADATA winsock_data;
  518.  
  519.    int socket_error = 0;
  520.  
  521.    WORD desired_winsock_version = 0x0101; // We'd like WINSOCK v1.1 at least
  522.  
  523.    BYTE major_version_required = 0;
  524.    BYTE minor_version_required = 0;
  525.  
  526.    ::ZeroMemory( &winsock_data, sizeof( winsock_data ) );
  527.  
  528.    socket_error = ::WSAStartup( desired_winsock_version, (LPWSADATA) &winsock_data );
  529.  
  530.    if ( socket_error != 0 )
  531.    {
  532.       TRACE( "WSAStartup failed with an error code of %d at line %d of %s\n", socket_error, __LINE__, __FILE__ );
  533.       AfxAbort();
  534.    }
  535.  
  536.    major_version_required = HIBYTE( desired_winsock_version );
  537.    minor_version_required = LOBYTE( desired_winsock_version );
  538.  
  539.    if ( (   LOBYTE( winsock_data.wVersion ) <  major_version_required ) ||
  540.         (   LOBYTE( winsock_data.wVersion ) == major_version_required ) &&
  541.         ( ( HIBYTE( winsock_data.wVersion ) <  minor_version_required ) ) )
  542.    {
  543.       TRACE( "Need a later version of Winsock\n" );
  544.    }
  545. }
  546.  
  547. void __stdcall CSimpleSocket::StopWindowsSockets( void )
  548. {
  549.    ::WSACleanup();
  550. }
  551.  
  552. void __stdcall CSimpleSocket::TranslateErrorCode( DWORD error_code, LPSTR destination_string, DWORD size_of_destination_string )
  553. {
  554.    switch( error_code )
  555.    {
  556.       /*
  557.       ** Following are Windows Sockets Library errors
  558.       */
  559.  
  560.       case WSAENOTSOCK:
  561.  
  562.         strncpy( destination_string, "WSAENOTSOCK, Socket operation on non-socket. A socket created in one process is used by another process.", size_of_destination_string );
  563.         return;
  564.  
  565.       case WSAEDESTADDRREQ:
  566.  
  567.         strncpy( destination_string, "WSAEDESTADDRREQ, Destination address required", size_of_destination_string );
  568.         return;
  569.  
  570.       case WSAEMSGSIZE:
  571.  
  572.         strncpy( destination_string, "WSAEMSGSIZE, Message too long", size_of_destination_string );
  573.         return;
  574.  
  575.       case WSAEPROTOTYPE:
  576.  
  577.         strncpy( destination_string, "WSAEPROTOTYPE, Protocol wrong type for socket", size_of_destination_string );
  578.         return;
  579.  
  580.       case WSAENOPROTOOPT:
  581.  
  582.         strncpy( destination_string, "WSAENOPROTOOPT, Protocol not available", size_of_destination_string );
  583.         return;
  584.  
  585.       case WSAEPROTONOSUPPORT:
  586.  
  587.         strncpy( destination_string, "WSAEPROTONOSUPPORT, Protocol not supported", size_of_destination_string );
  588.         return;
  589.  
  590.       case WSAESOCKTNOSUPPORT:
  591.  
  592.         strncpy( destination_string, "WSAESOCKTNOSUPPORT, Socket type not supported", size_of_destination_string );
  593.         return;
  594.  
  595.       case WSAEOPNOTSUPP:
  596.  
  597.         strncpy( destination_string, "WSAEOPNOTSUPP, Operation not supported on socket", size_of_destination_string );
  598.         return;
  599.  
  600.       case WSAEPFNOSUPPORT:
  601.  
  602.         strncpy( destination_string, "WSAEPFNOSUPPORT, Protocol family not supported", size_of_destination_string );
  603.         return;
  604.  
  605.       case WSAEAFNOSUPPORT:
  606.  
  607.         strncpy( destination_string, "WSEAFNOSUPPORT, Address family not supported by protocol family", size_of_destination_string );
  608.         return;
  609.  
  610.       case WSAEADDRINUSE:
  611.  
  612.         strncpy( destination_string, "WSAEADDRINUSE, Triggered by bind() because a process went down without closing a socket.", size_of_destination_string );
  613.         return;
  614.  
  615.       case WSAEADDRNOTAVAIL:
  616.  
  617.         strncpy( destination_string, "WSAEADDRNOTAVAIL, Can't assign requested address", size_of_destination_string );
  618.         return;
  619.  
  620.       case WSAENETDOWN:
  621.  
  622.         strncpy( destination_string, "WSAENETDOWN, Network is down", size_of_destination_string );
  623.         return;
  624.  
  625.       case WSAENETUNREACH:
  626.  
  627.         strncpy( destination_string, "WSAENETUNREACH, Network is unreachable", size_of_destination_string );
  628.         return;
  629.  
  630.       case WSAENETRESET:
  631.  
  632.         strncpy( destination_string, "WSAENETRESET, Network dropped connection or reset", size_of_destination_string );
  633.         return;
  634.  
  635.       case WSAECONNABORTED:
  636.  
  637.         strncpy( destination_string, "WSAECONNABORTED, Software caused connection abort", size_of_destination_string );
  638.         return;
  639.  
  640.       case WSAECONNRESET:
  641.  
  642.         strncpy( destination_string, "WSAECONNRESET, Connection reset by peer", size_of_destination_string );
  643.         return;
  644.  
  645.       case WSAENOBUFS:
  646.  
  647.         strncpy( destination_string, "WSAENOBUFS, No buffer space available.", size_of_destination_string );
  648.         return;
  649.  
  650.       case WSAEISCONN:
  651.  
  652.         strncpy( destination_string, "WSAEISCONN, Socket is already connected", size_of_destination_string );
  653.         return;
  654.  
  655.       case WSAENOTCONN:
  656.  
  657.         strncpy( destination_string, "WSAENOTCONN, Socket is not connected", size_of_destination_string );
  658.         return;
  659.  
  660.       case WSAESHUTDOWN:
  661.  
  662.         strncpy( destination_string, "WSAESHUTDOWN, Can't send after socket shutdown", size_of_destination_string );
  663.         return;
  664.  
  665.       case WSAETIMEDOUT:
  666.  
  667.         strncpy( destination_string, "WSAETIMEDOUT, Connection timed out", size_of_destination_string );
  668.         return;
  669.  
  670.       case WSAECONNREFUSED:
  671.  
  672.         strncpy( destination_string, "WSAECONNREFUSED, Connection refused", size_of_destination_string );
  673.         return;
  674.  
  675.       case WSAEHOSTDOWN:
  676.  
  677.         strncpy( destination_string, "WSAEHOSTDOWN, Networking subsystem not started", size_of_destination_string );
  678.         return;
  679.  
  680.       case WSAEHOSTUNREACH:
  681.  
  682.         strncpy( destination_string, "WSAEHOSTUNREACH, No route to host", size_of_destination_string );
  683.         return;
  684.  
  685.       case WSAEWOULDBLOCK:
  686.  
  687.         strncpy( destination_string, "WSAEWOULDBLOCK, Operation would block", size_of_destination_string );
  688.         return;
  689.  
  690.       case WSAEINPROGRESS:
  691.  
  692.         strncpy( destination_string, "WSAEINPROGRESS, Operation now in progress", size_of_destination_string );
  693.         return;
  694.  
  695.       case WSAEALREADY:
  696.  
  697.         strncpy( destination_string, "WSAEALREADY, Operation already in progress", size_of_destination_string );
  698.         return;
  699.  
  700.       case WSAEINTR:
  701.  
  702.         strncpy( destination_string, "WSAEALREADY, Operation was interrupted", size_of_destination_string );
  703.         return;
  704.  
  705.       case WSAEBADF:
  706.  
  707.         strncpy( destination_string, "WSAEBADF, Bad file number", size_of_destination_string );
  708.         return;
  709.  
  710.       case WSAEACCES:
  711.  
  712.         strncpy( destination_string, "WSAEACCES, Access is denied", size_of_destination_string );
  713.         return;
  714.  
  715.       case WSAEFAULT:
  716.  
  717.         strncpy( destination_string, "WSAEFAULT, Bad memory address", size_of_destination_string );
  718.         return;
  719.  
  720.       case WSAEINVAL:
  721.  
  722.         strncpy( destination_string, "WSAEINVAL, The socket has not been bound with bind() or is already connected", size_of_destination_string );
  723.         return;
  724.  
  725.       case WSAEMFILE:
  726.  
  727.         strncpy( destination_string, "WSAEMFILE, No more file descriptors are available", size_of_destination_string );
  728.         return;
  729.  
  730.       case WSAETOOMANYREFS:
  731.  
  732.         strncpy( destination_string, "WSAETOOMANYREFS, Undocumented WinSock error", size_of_destination_string );
  733.         return;
  734.  
  735.       case WSAENAMETOOLONG:
  736.  
  737.         strncpy( destination_string, "WSAENAMETOOLONG, Undocumented WinSock error", size_of_destination_string );
  738.         return;
  739.  
  740.       case WSAENOTEMPTY:
  741.  
  742.         strncpy( destination_string, "WSAENOTEMPTY, Undocumented WinSock error", size_of_destination_string );
  743.         return;
  744.  
  745.       case WSAEPROCLIM:
  746.  
  747.         strncpy( destination_string, "WSAEPROCLIM, Undocumented WinSock error", size_of_destination_string );
  748.         return;
  749.  
  750.       case WSAEUSERS:
  751.  
  752.         strncpy( destination_string, "WSAEUSERS, Undocumented WinSock error", size_of_destination_string );
  753.         return;
  754.  
  755.       case WSAEDQUOT:
  756.  
  757.         strncpy( destination_string, "WSAEDQUOT, Undocumented WinSock error", size_of_destination_string );
  758.         return;
  759.  
  760.       case WSAESTALE:
  761.  
  762.         strncpy( destination_string, "WSAESTALE, Undocumented WinSock error", size_of_destination_string );
  763.         return;
  764.  
  765.       case WSAEREMOTE:
  766.  
  767.         strncpy( destination_string, "WSAEREMOTE, Undocumented WinSock error", size_of_destination_string );
  768.         return;
  769.  
  770.       case WSAEDISCON:
  771.  
  772.         strncpy( destination_string, "WSAEDISCON, Circuit was gracefully terminated", size_of_destination_string );
  773.         return;
  774.  
  775.       case WSASYSNOTREADY:
  776.  
  777.         strncpy( destination_string, "WSASYSNOTREADY, The underlying network subsystem is not ready for network communication", size_of_destination_string );
  778.         return;
  779.  
  780.       case WSAVERNOTSUPPORTED:
  781.  
  782.         strncpy( destination_string, "WSAVERNOTSUPPORTED, The version of Windows Sockets API support requested is not provided by this particular Windows Sockets implementation", size_of_destination_string );
  783.         return;
  784.  
  785.       case WSANOTINITIALISED:
  786.  
  787.         strncpy( destination_string, "WSANOTINITIALISED, WSAStartup() has not been called", size_of_destination_string );
  788.         return;
  789.  
  790.       case WSAHOST_NOT_FOUND:
  791.  
  792.         strncpy( destination_string, "WSAHOST_NOT_FOUND, Authoritative answer host not found", size_of_destination_string );
  793.         return;
  794.  
  795.       case WSATRY_AGAIN:
  796.  
  797.         strncpy( destination_string, "WSATRY_AGAIN, Non-authoritative answer host not found or SERVERFAIL", size_of_destination_string );
  798.         return;
  799.  
  800.       case WSANO_RECOVERY:
  801.  
  802.         strncpy( destination_string, "WSANO_RECOVERY, Non recoverable errors, FORMERR, REFUSED, NOTIMP", size_of_destination_string );
  803.         return;
  804.  
  805.       case WSANO_DATA:
  806.  
  807.         strncpy( destination_string, "WSANO_DATA or WSANO_ADDRESS, Valid name, no data record of requested type", size_of_destination_string );
  808.         return;
  809.  
  810.       default:
  811.  
  812.          {
  813.             TCHAR message_string[ 129 ];
  814.  
  815.             wsprintf( (LPTSTR) message_string, (LPCSTR) TEXT( "Unknown WinSock Error Number %d" ), error_code );
  816.             strncpy( destination_string, message_string, size_of_destination_string );
  817.          }
  818.  
  819.          return;
  820.    }
  821. }
  822.  
  823. void CSimpleSocket::Write( const VOID *buffer, const long number_of_bytes_to_write )
  824. {
  825.    ASSERT_VALID( this );
  826.    ASSERT( buffer != NULL );
  827.    ASSERT( number_of_bytes_to_write > 0L );
  828.  
  829.    if ( buffer == NULL )
  830.    {
  831.       return;
  832.    }
  833.  
  834.    if ( m_SocketID == INVALID_SOCKET )
  835.    {
  836.       return;
  837.    }
  838.  
  839.    BYTE *byte_buffer = (BYTE *) NULL;
  840.  
  841.    byte_buffer = (BYTE *) buffer;
  842.  
  843.    if ( byte_buffer == (BYTE *) NULL )
  844.    {
  845.       return;
  846.    }
  847.  
  848.    /*
  849.    ** Loop until the bytes are sent or until we give up
  850.    */
  851.  
  852.    BOOL bytes_were_sent = FALSE;
  853.  
  854.    int number_of_bytes_sent = 0;
  855.    int loop_count           = 0;
  856.  
  857.    while( bytes_were_sent == FALSE && loop_count < 100 )
  858.    {
  859.       number_of_bytes_sent = ::send( m_SocketID, (const char *) byte_buffer, number_of_bytes_to_write, 0 );
  860.  
  861.       if ( number_of_bytes_sent == SOCKET_ERROR )
  862.       {
  863.          m_ErrorCode = ::WSAGetLastError();
  864.  
  865.          char temp_string[ 513 ];
  866.  
  867.          TranslateErrorCode( m_ErrorCode, temp_string, sizeof( temp_string ) );
  868.  
  869.          TRACE1( "CSimpleSocket::Write, %s\n", temp_string );
  870.  
  871.          if ( m_ErrorCode != WSAENOBUFS &&
  872.               m_ErrorCode != WSAEINPROGRESS )
  873.          {
  874.             if ( m_ErrorCode == WSAENOTCONN  ||
  875.                  m_ErrorCode == WSAENETRESET ||
  876.                  m_ErrorCode == WSAESHUTDOWN )
  877.             {
  878.                /*
  879.                ** Someone hung up on us or unplugged our lan cable
  880.                */
  881.  
  882.                m_SocketID = INVALID_SOCKET;
  883.                m_hFile    = CFile::hFileNull;
  884.             }
  885.  
  886.             return;
  887.          }
  888.          else
  889.          {
  890.             loop_count++;
  891.          }
  892.       }
  893.       else
  894.       {
  895.          bytes_were_sent = TRUE;
  896.       }
  897.    }
  898. }
  899.  
  900. void CSimpleSocket::Write( const CString& string_to_write )
  901. {
  902.    ASSERT_VALID( this );
  903.  
  904.    CString temp_string;
  905.  
  906.    temp_string = string_to_write;
  907.  
  908.    Write( (VOID *) temp_string.GetBuffer( temp_string.GetLength() + 1 ), temp_string.GetLength() );
  909. }
  910.  
  911. #pragma warning( default : 4100 )
  912.